﻿/*
    Copyright (c) 2012, Matías López
    All rights reserved.

    Redistribution and use in source and binary forms, with or without modification, are permitted 
    provided that the following conditions are met:
        *   Redistributions of source code must retain the above copyright notice, this list of 
            conditions and the following disclaimer.
        *   Redistributions in binary form must reproduce the above copyright notice, this list of 
            conditions and the following disclaimer in the documentation and/or other materials 
            provided with the distribution.
        *   Neither the name of Matías López nor the names of its contributors may be used to 
            endorse or promote products derived from this software without specific prior written 
            permission.
    
    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR 
    IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY 
    AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 
    CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
    CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 
    SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 
    THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 
    OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
    POSSIBILITY OF SUCH DAMAGE.
 */

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;

namespace mana.CodeGenerator
{
    /// <summary>
    /// Genera archivos de código.
    /// </summary>
    public class GeneradorCodigo
    {
        protected int _tabs;
        
        public GeneradorCodigo()
        {
            _tabs = 0;
        }

        protected void Agregar(StringBuilder sb, string texto)
        {
            Agregar(sb, texto, false);
        }

        protected void Agregar(StringBuilder sb, string texto, bool incluirTabs)
        {
            string tabs = string.Empty;
            if (incluirTabs)
            {
                StringBuilder sbTabs = new StringBuilder();
                for (int i = 1; i <= _tabs; i++)
                {
                    sbTabs.Append("\t");
                }

                tabs = ObtenerString(sbTabs, string.Empty);
            }

            sb.Append(tabs + texto);
        }

        protected void AgregarLinea(StringBuilder sb, string texto)
        {
            AgregarLinea(sb, texto, true);
        }

        protected void AgregarLinea(StringBuilder sb, string texto, bool incluirTabs)
        {
            string tabs = string.Empty;

            if (incluirTabs)
            {
                StringBuilder sbTabs = new StringBuilder();
                for (int i = 1; i <= _tabs; i++)
                {
                    sbTabs.Append("\t");
                }

                tabs = ObtenerString(sbTabs, Environment.NewLine);
            }

            sb.AppendLine(tabs + texto);
        }

        protected string ObtenerString(StringBuilder sb)
        {
            return ObtenerString(sb, string.Empty);
        }

        protected string ObtenerString(StringBuilder sb, string eliminarDelFinal)
        {
            return sb.ToString().TrimEnd(eliminarDelFinal.ToCharArray());
        }

        /// <summary>
        /// Genera el archivo. 
        /// Crea los directorios necesarios (en caso de que no existan) para guardar el archivo.
        /// </summary>
        /// <param name="pathArchivo"></param>
        protected virtual void GenerarArchivo(Objeto objeto, Plantilla plantilla, string pathArchivo)
        {
            string directorioArchivosGenerados = "GeneratedFiles";
            string pathCompleto = string.Format("{0}\\{1}", directorioArchivosGenerados, pathArchivo);

            string[] pathDirectorios = Path.GetDirectoryName(pathCompleto).Split(Path.DirectorySeparatorChar);
            string directorioActualPathCompleto = string.Empty;
            foreach (string directorioActual in pathDirectorios)
            {
                directorioActualPathCompleto = Path.Combine(directorioActualPathCompleto, directorioActual);

                if (!Directory.Exists(directorioActualPathCompleto))
                    Directory.CreateDirectory(directorioActualPathCompleto);
            }
            
            using (StreamWriter escritor = new StreamWriter(pathCompleto, false, Encoding.UTF8))
            {
                escritor.Write(plantilla.Contenido);
            }
        }
    }

    /// <summary>
    /// Genera archivos de código C#.
    /// </summary>
    public class GeneradorCodigoCS : GeneradorCodigo
    {
        public GeneradorCodigoCS()
        { }

        public void GenerarArchivoDeObjetoParaAzure(Objeto objeto)
        {
            var plantilla = Internal_Plantillas.ObtenerPlantillaCs(PlantillaCSNombre.ObjectFileAzure);

            plantilla.EstablecerCampo("Namespace", objeto.EspacioDeNombre);
            plantilla.EstablecerCampo("Nombre", objeto.Nombre);
            plantilla.EstablecerCampo("NombreMinuscula", objeto.NombreMinuscula);
            plantilla.EstablecerCampo("NombrePlural", objeto.NombrePlural);
            
            StringBuilder sbAtributos= new StringBuilder();
            StringBuilder sbConstructorParametrosDeclaracion = new StringBuilder();
            StringBuilder sbDeclaracionValidaciones = new StringBuilder();
            StringBuilder sbValidaciones = new StringBuilder();
            StringBuilder sbAsignaciones = new StringBuilder();
            StringBuilder sbPropiedades = new StringBuilder();
            StringBuilder sbEntidadPropiedades = new StringBuilder();
            StringBuilder sbInstanciarEntidadDesdeObjeto = new StringBuilder();
            StringBuilder sbActualizarEntidadDesdeObjeto = new StringBuilder();
            StringBuilder sbInicializarObjetoDesdeEntidad = new StringBuilder();
            StringBuilder sbConstructorParametros = new StringBuilder();

            _tabs = 0;
            foreach (Propiedad propiedad in objeto.Propiedades)
            {
                //  ATRIBUTOS
                //--------------------------------------------------------------------------------------
                _tabs = 2;
                AgregarLinea(sbAtributos, "private " + propiedad.Tipo + " _" + propiedad.NombreMinuscula + ";");
                //--------------------------------------------------------------------------------------

                //  CONSTRUCTOR PARAMETROS DECLARACION
                //--------------------------------------------------------------------------------------
                Agregar(sbConstructorParametrosDeclaracion, propiedad.Tipo + " " + propiedad.NombreMinuscula + ", ");
                //--------------------------------------------------------------------------------------
                
                //  DECLARACION VALIDACIONES
                //--------------------------------------------------------------------------------------
                _tabs++;
                AgregarLinea(sbDeclaracionValidaciones, "public static void " + propiedad.Nombre + "(" + propiedad.Tipo + " value)");
                AgregarLinea(sbDeclaracionValidaciones, "{");
                AgregarLinea(sbDeclaracionValidaciones, "}");
                AgregarLinea(sbDeclaracionValidaciones, string.Empty);
                //--------------------------------------------------------------------------------------

                //  VALIDACIONES
                //--------------------------------------------------------------------------------------
                AgregarLinea(sbValidaciones, "Validations." + propiedad.Nombre + "(" + propiedad.NombreMinuscula + ");");
                //--------------------------------------------------------------------------------------

                //  ASIGNACIONES
                //--------------------------------------------------------------------------------------
                AgregarLinea(sbAsignaciones, "_" + propiedad.NombreMinuscula + " = " + propiedad.NombreMinuscula + ";");
                //--------------------------------------------------------------------------------------

                //  PROPIEDADES
                //--------------------------------------------------------------------------------------
                _tabs--;
                AgregarLinea(sbPropiedades, "public " + propiedad.Tipo + " " + propiedad.Nombre);
                AgregarLinea(sbPropiedades, "{");

                _tabs++;
                AgregarLinea(sbPropiedades, "get { return _" + propiedad.NombreMinuscula + "; }");

                if (!propiedad.SoloLectura)
                {
                    AgregarLinea(sbPropiedades, "set");
                    AgregarLinea(sbPropiedades, "{");

                    _tabs++;
                    AgregarLinea(sbPropiedades, "Validations." + propiedad.Nombre + "(value);");
                    AgregarLinea(sbPropiedades, "_" + propiedad.NombreMinuscula + " = value;");

                    _tabs--;
                    AgregarLinea(sbPropiedades, "}");
                }
                
                _tabs--;
                AgregarLinea(sbPropiedades, "}");
                AgregarLinea(sbPropiedades, string.Empty);
                //--------------------------------------------------------------------------------------

                //  PROPIEDADES ENTIDAD
                //--------------------------------------------------------------------------------------
                _tabs += 3;
                AgregarLinea(sbEntidadPropiedades, "public " + propiedad.Tipo + " " + propiedad.Nombre + " { get; set; }");
                //--------------------------------------------------------------------------------------

                //  INSTANCIAR ENTIDAD DESDE OBJETO
                //--------------------------------------------------------------------------------------
                _tabs++;
                AgregarLinea(sbInstanciarEntidadDesdeObjeto, propiedad.Nombre + " = obj." + propiedad.Nombre + ",");
                //--------------------------------------------------------------------------------------

                //  ACTUALIZAR ENTIDAD DESDE OBJETO
                //--------------------------------------------------------------------------------------
                _tabs--;
                if (!propiedad.SoloLectura)
                    AgregarLinea(sbActualizarEntidadDesdeObjeto, "entity." + propiedad.Nombre + " = obj." + propiedad.Nombre + ";");
                //--------------------------------------------------------------------------------------

                //  INICIALIZAR OBJETO DESDE ENTIDAD
                //--------------------------------------------------------------------------------------
                _tabs++;
                AgregarLinea(sbInicializarObjetoDesdeEntidad, "entity." + propiedad.Nombre + ",");
                //--------------------------------------------------------------------------------------

                //  CONSTRUCTOR PARAMETROS
                //--------------------------------------------------------------------------------------
                Agregar(sbConstructorParametros, propiedad.NombreMinuscula + ", ");
                //--------------------------------------------------------------------------------------
            }
            plantilla.EstablecerCampo("Atributos", ObtenerString(sbAtributos, Environment.NewLine));
            plantilla.EstablecerCampo("ConstructorParametrosDeclaracion", ObtenerString(sbConstructorParametrosDeclaracion, ", "));
            plantilla.EstablecerCampo("DeclaracionValidaciones", ObtenerString(sbDeclaracionValidaciones));
            plantilla.EstablecerCampo("Validaciones", ObtenerString(sbValidaciones, Environment.NewLine));
            plantilla.EstablecerCampo("Asignaciones", ObtenerString(sbAsignaciones, Environment.NewLine));
            plantilla.EstablecerCampo("Propiedades", ObtenerString(sbPropiedades));
            plantilla.EstablecerCampo("EntidadPropiedades", ObtenerString(sbEntidadPropiedades));
            plantilla.EstablecerCampo("InstanciarEntidadDesdeObjeto", ObtenerString(sbInstanciarEntidadDesdeObjeto, "," + Environment.NewLine));
            plantilla.EstablecerCampo("ActualizarEntidadDesdeObjeto", ObtenerString(sbActualizarEntidadDesdeObjeto, Environment.NewLine));
            plantilla.EstablecerCampo("InicializarObjetoDesdeEntidad", ObtenerString(sbInicializarObjetoDesdeEntidad, "," + Environment.NewLine));
            plantilla.EstablecerCampo("ConstructorParametros", ObtenerString(sbConstructorParametros, ", " + Environment.NewLine));

            GenerarArchivoLib(objeto, plantilla, objeto.NombrePlural);
        }

        public void GenerarArchivoDeObjetoParaSQL(Objeto objeto)
        {
            var plantilla = Internal_Plantillas.ObtenerPlantillaCs(PlantillaCSNombre.ObjectFileSQL);

            plantilla.EstablecerCampo("Namespace", objeto.EspacioDeNombre);
            plantilla.EstablecerCampo("Nombre", objeto.Nombre);
            plantilla.EstablecerCampo("NombreMinuscula", objeto.NombreMinuscula);
            plantilla.EstablecerCampo("NombrePlural", objeto.NombrePlural);

            StringBuilder sbAtributos = new StringBuilder();
            StringBuilder sbConstructorParametrosDeclaracion = new StringBuilder();
            StringBuilder sbDeclaracionValidaciones = new StringBuilder();
            StringBuilder sbValidaciones = new StringBuilder();
            StringBuilder sbAsignaciones = new StringBuilder();
            StringBuilder sbPropiedades = new StringBuilder();
            StringBuilder sbConstructorParametros = new StringBuilder();
            StringBuilder sbDeclaracionCamposAccesoADatos = new StringBuilder();
            StringBuilder sbDeclaracionParametrosSQLTodos = new StringBuilder();
            StringBuilder sbDeclaracionParametrosSQLLecturaEscritura = new StringBuilder();
            StringBuilder sbEnumeracionNombresCamposSchemaTodos = new StringBuilder();
            StringBuilder sbEnumeracionNombresCamposSchemaLecturaEscritura = new StringBuilder();
            StringBuilder sbEnumeracionCamposSQLTodos = new StringBuilder();
            StringBuilder sbEnumeracionParametrosSQLTodos = new StringBuilder();
            StringBuilder sbEnumeracionParametrosSQLLecturaEscritura = new StringBuilder();
            StringBuilder sbEnumeracionCamposSQLLecturaEscrituraConValores = new StringBuilder();
            StringBuilder sbParametrosMaterializacion = new StringBuilder();
            
            _tabs = 0;
            int propiedadIndice = 0;
            int propiedadLecturaEscrituraIndice = 0;
            foreach (var propiedad in objeto.Propiedades)
            {
                //  ATRIBUTOS
                //--------------------------------------------------------------------------------------
                _tabs = 2;
                AgregarLinea(sbAtributos, "private " + propiedad.Tipo + " _" + propiedad.NombreMinuscula + ";");
                //--------------------------------------------------------------------------------------

                //  CONSTRUCTOR PARAMETROS DECLARACION
                //--------------------------------------------------------------------------------------
                Agregar(sbConstructorParametrosDeclaracion, propiedad.Tipo + " " + propiedad.NombreMinuscula + ", ");
                //--------------------------------------------------------------------------------------

                //  DECLARACION VALIDACIONES
                //--------------------------------------------------------------------------------------
                _tabs++;
                AgregarLinea(sbDeclaracionValidaciones, "public static void " + propiedad.Nombre + "(" + propiedad.Tipo + " valor)");
                AgregarLinea(sbDeclaracionValidaciones, "{");
                AgregarLinea(sbDeclaracionValidaciones, "}");
                AgregarLinea(sbDeclaracionValidaciones, string.Empty);
                //--------------------------------------------------------------------------------------

                //  VALIDACIONES
                //--------------------------------------------------------------------------------------
                AgregarLinea(sbValidaciones, "Validations." + propiedad.Nombre + "(" + propiedad.NombreMinuscula + ");");
                //--------------------------------------------------------------------------------------

                //  ASIGNACIONES
                //--------------------------------------------------------------------------------------
                AgregarLinea(sbAsignaciones, "_" + propiedad.NombreMinuscula + " = " + propiedad.NombreMinuscula + ";");
                //--------------------------------------------------------------------------------------

                //  PROPIEDADES
                //--------------------------------------------------------------------------------------
                _tabs--;
                AgregarLinea(sbPropiedades, "public " + propiedad.Tipo + " " + propiedad.Nombre);
                AgregarLinea(sbPropiedades, "{");

                _tabs++;
                AgregarLinea(sbPropiedades, "get { return _" + propiedad.NombreMinuscula + "; }");

                if (!propiedad.SoloLectura)
                {
                    AgregarLinea(sbPropiedades, "set");
                    AgregarLinea(sbPropiedades, "{");

                    _tabs++;
                    AgregarLinea(sbPropiedades, "Validations." + propiedad.Nombre + "(value);");
                    AgregarLinea(sbPropiedades, "_" + propiedad.NombreMinuscula + " = value;");

                    _tabs--;
                    AgregarLinea(sbPropiedades, "}");
                }

                _tabs--;
                AgregarLinea(sbPropiedades, "}");
                AgregarLinea(sbPropiedades, string.Empty);
                //--------------------------------------------------------------------------------------

                //  CONSTRUCTOR PARAMETROS
                //--------------------------------------------------------------------------------------
                Agregar(sbConstructorParametros, propiedad.NombreMinuscula + ", ");
                //--------------------------------------------------------------------------------------

                //  DECLARACION CAMPOS ACCESO A DATOS
                //--------------------------------------------------------------------------------------
                _tabs += 3;
                AgregarLinea(sbDeclaracionCamposAccesoADatos, string.Format("public static SchemaFieldName {0} = new SchemaFieldName(\"{0}\");", propiedad.Nombre));
                //--------------------------------------------------------------------------------------

                //  DECLARACION PARAMETROS SQL
                //--------------------------------------------------------------------------------------
                //  Todos
                //_tabs++;
                string declaracionParametroSql = string.Format("parameters.Add(new SqlParameter(\"@{0}\", obj.{0}));", propiedad.Nombre);
                AgregarLinea(sbDeclaracionParametrosSQLTodos, declaracionParametroSql);
                
                //  Lectura/Escritura
                if (!propiedad.SoloLectura)
                    AgregarLinea(sbDeclaracionParametrosSQLLecturaEscritura, declaracionParametroSql);
                //--------------------------------------------------------------------------------------

                //  ENUMERACIÓN NOMBRE CAMPOS SQL
                //--------------------------------------------------------------------------------------
                //  Todos
                string enumeracionCampoSql = string.Format("@{0}, ", propiedad.Nombre);
                Agregar(sbEnumeracionParametrosSQLTodos, enumeracionCampoSql);

                //  Lectura/Escritura
                if (!propiedad.SoloLectura)
                    Agregar(sbEnumeracionParametrosSQLLecturaEscritura, enumeracionCampoSql);
                //--------------------------------------------------------------------------------------

                //  ENUMERACIÓN NOMBRES CAMPOS SCHEMA 
                //--------------------------------------------------------------------------------------
                //  Todos
                string enumeracionNombreCampoSchema = string.Format("Schema.{0}, ", propiedad.Nombre);
                Agregar(sbEnumeracionNombresCamposSchemaTodos, enumeracionNombreCampoSchema);

                //  Lectura/Escritura
                if (!propiedad.SoloLectura)
                    Agregar(sbEnumeracionNombresCamposSchemaLecturaEscritura, enumeracionNombreCampoSchema);
                //--------------------------------------------------------------------------------------

                //  ENUMERACIÓN CAMPOS SQL (todos)
                //--------------------------------------------------------------------------------------
                propiedadIndice++;
                string propiedadIndiceEnumeracion = string.Format("{{{0}}}", propiedadIndice);
                Agregar(sbEnumeracionCamposSQLTodos, string.Format("{0}, ", propiedadIndiceEnumeracion));
                //--------------------------------------------------------------------------------------

                // ENUMERACION CAMPOS SQL CON VALORES
                //--------------------------------------------------------------------------------------
                if (!propiedad.SoloLectura)
                {
                    propiedadLecturaEscrituraIndice++;
                    Agregar(sbEnumeracionCamposSQLLecturaEscrituraConValores, string.Format("{{{0}}} = {1}", propiedadLecturaEscrituraIndice, enumeracionCampoSql));
                }
                //--------------------------------------------------------------------------------------

                //  PARAMETROS MATERIALIZACION
                //--------------------------------------------------------------------------------------
                _tabs += 2;
                AgregarLinea(sbParametrosMaterializacion, ObtenerParametroDeMaterializacion(propiedad));
                //--------------------------------------------------------------------------------------
            }

            plantilla.EstablecerCampo("Atributos", ObtenerString(sbAtributos, Environment.NewLine));
            plantilla.EstablecerCampo("ConstructorParametrosDeclaracion", ObtenerString(sbConstructorParametrosDeclaracion, ", "));
            plantilla.EstablecerCampo("DeclaracionValidaciones", ObtenerString(sbDeclaracionValidaciones));
            plantilla.EstablecerCampo("Validaciones", ObtenerString(sbValidaciones, Environment.NewLine));
            plantilla.EstablecerCampo("Asignaciones", ObtenerString(sbAsignaciones, Environment.NewLine));
            plantilla.EstablecerCampo("Propiedades", ObtenerString(sbPropiedades));
            plantilla.EstablecerCampo("ConstructorParametros", ObtenerString(sbConstructorParametros, ", " + Environment.NewLine));
            plantilla.EstablecerCampo("DeclaracionCamposAccesoADatos", ObtenerString(sbDeclaracionCamposAccesoADatos, Environment.NewLine));
            plantilla.EstablecerCampo("DeclaracionParametrosSQLTodos", ObtenerString(sbDeclaracionParametrosSQLTodos, Environment.NewLine));
            plantilla.EstablecerCampo("DeclaracionParametrosSQLLecturaEscritura", ObtenerString(sbDeclaracionParametrosSQLLecturaEscritura, Environment.NewLine));
            plantilla.EstablecerCampo("EnumeracionNombresCamposSchemaTodos", ObtenerString(sbEnumeracionNombresCamposSchemaTodos, ", "));
            plantilla.EstablecerCampo("EnumeracionNombresCamposSchemaLecturaEscritura", ObtenerString(sbEnumeracionNombresCamposSchemaLecturaEscritura, ", "));
            plantilla.EstablecerCampo("EnumeracionParametrosSQLTodos", ObtenerString(sbEnumeracionParametrosSQLTodos, ", "));
            plantilla.EstablecerCampo("EnumeracionParametrosSQLLecturaEscritura", ObtenerString(sbEnumeracionParametrosSQLLecturaEscritura, ", "));
            plantilla.EstablecerCampo("EnumeracionCamposSQLTodos", ObtenerString(sbEnumeracionCamposSQLTodos, ", "));
            plantilla.EstablecerCampo("EnumeracionCamposSQLLecturaEscrituraConValores", ObtenerString(sbEnumeracionCamposSQLLecturaEscrituraConValores, ", "));
            plantilla.EstablecerCampo("EnumeracionCamposSQLLecturaEscrituraConValoresUltimoIndice", Convert.ToString(propiedadLecturaEscrituraIndice + 1));
            plantilla.EstablecerCampo("ParametrosMaterializacion", ObtenerString(sbParametrosMaterializacion, ", " + Environment.NewLine));

            GenerarArchivoLib(objeto, plantilla, objeto.NombrePlural);
        }

        public void GenerarArchivoVerTodosCodeBehind(Objeto objeto)
        {
            var plantilla = Internal_Plantillas.ObtenerPlantillaCs(PlantillaCSNombre.ViewAllCodeBehind);

            plantilla.EstablecerCampo("Namespace", objeto.EspacioDeNombre);
            plantilla.EstablecerCampo("Nombre", objeto.Nombre);
            plantilla.EstablecerCampo("NombrePlural", objeto.NombrePlural);
            plantilla.EstablecerCampo("NombrePluralUppercase", objeto.NombrePlural.ToUpper());

            StringBuilder sbNuevoItemParametros = new StringBuilder();
            StringBuilder sbEditarItemEstablecerCampos = new StringBuilder();
            StringBuilder sbNuevoItemLimpiarControles = new StringBuilder();
            StringBuilder sbEditarItemLimpiarControles = new StringBuilder();
            StringBuilder sbEditarItemEstablecerControles = new StringBuilder();
            

            _tabs = 0;
            foreach (var propiedad in objeto.Propiedades)
            {
                //  NUEVO ITEM PARAMETROS
                //--------------------------------------------------------------------------------------
                Agregar(sbNuevoItemParametros, string.Format("txtNew{0}{1}.Text, ", objeto.Nombre, propiedad.Nombre));
                //--------------------------------------------------------------------------------------

                //  EDITAR ITEM ESTABLECER CAMPOS
                //--------------------------------------------------------------------------------------
                _tabs = 3;
                string controlPrefijo = string.Empty;
                if (propiedad.SoloLectura)
                    controlPrefijo = "lbl";
                else
                    controlPrefijo = "txt";
                
                if (!propiedad.SoloLectura)
                    AgregarLinea(sbEditarItemEstablecerCampos, string.Format("selectedItem.{0} = {1}Edit{2}{0}.Text;", propiedad.Nombre, controlPrefijo, objeto.Nombre));
                //--------------------------------------------------------------------------------------

                //  LIMPIAR CONTROLES
                //--------------------------------------------------------------------------------------
                //  Nuevo item
                _tabs = 3;
                Agregar(sbNuevoItemLimpiarControles, string.Format("txtNew{0}{1}.Text = ", objeto.Nombre, propiedad.Nombre));

                //  Editar item
                Agregar(sbEditarItemLimpiarControles, string.Format("{0}Edit{1}{2}.Text = ", controlPrefijo, objeto.Nombre, propiedad.Nombre));
                //--------------------------------------------------------------------------------------

                //  EDITAR ITEM ESTABLECER CONTROLES
                //--------------------------------------------------------------------------------------
                _tabs = 6;
                AgregarLinea(sbEditarItemEstablecerControles, string.Format("{0}Edit{1}{2}.Text = selectedItem.{2};", controlPrefijo, objeto.Nombre, propiedad.Nombre));
                //--------------------------------------------------------------------------------------
            }

            plantilla.EstablecerCampo("NuevoItemParametros", ObtenerString(sbNuevoItemParametros, ", "));
            plantilla.EstablecerCampo("EditarItemEstablecerCampos", ObtenerString(sbEditarItemEstablecerCampos, Environment.NewLine));
            plantilla.EstablecerCampo("NuevoItemLimpiarControles", ObtenerString(sbNuevoItemLimpiarControles, " = "));
            plantilla.EstablecerCampo("EditarItemLimpiarControles", ObtenerString(sbEditarItemLimpiarControles, " = "));
            plantilla.EstablecerCampo("EditarItemEstablecerControles", ObtenerString(sbEditarItemEstablecerControles, Environment.NewLine));

            GenerarArchivoWeb(objeto, plantilla, "ViewAll.aspx");
        }

        public void GenerarArchivoVerTodosDesigner(Objeto objeto)
        {
            var plantilla = Internal_Plantillas.ObtenerPlantillaCs(PlantillaCSNombre.ViewAllDesigner);

            plantilla.EstablecerCampo("Namespace", objeto.EspacioDeNombre);
            plantilla.EstablecerCampo("Nombre", objeto.Nombre);
            plantilla.EstablecerCampo("NombrePlural", objeto.NombrePlural);

            var sbNuevoItemDeclaracionControles = new StringBuilder();
            var sbEditarItemDeclaracionControles = new StringBuilder();

            _tabs = 2;
            foreach (var propiedad in objeto.Propiedades)
            {
                // DECLARACION CONTROLES
                //--------------------------------------------------------------------------------------
                string controlTipo = string.Empty;
                string controlPrefijo = string.Empty;
                if (propiedad.SoloLectura)
                {
                    controlTipo = "Label";
                    controlPrefijo = "lbl";
                }
                else
                {
                    controlTipo = "TextBox";
                    controlPrefijo = "txt";
                }

                //  Nuevo item
                AgregarLinea(sbNuevoItemDeclaracionControles, "/// <summary>");
                AgregarLinea(sbNuevoItemDeclaracionControles, string.Format("/// txtNew{0}{1} control.", objeto.Nombre, propiedad.Nombre));
                AgregarLinea(sbNuevoItemDeclaracionControles, "/// </summary>");
                AgregarLinea(sbNuevoItemDeclaracionControles, "/// <remarks>");
                AgregarLinea(sbNuevoItemDeclaracionControles, "/// Auto-generated field.");
                AgregarLinea(sbNuevoItemDeclaracionControles, "/// To modify move field declaration from designer file to code-behind file.");
                AgregarLinea(sbNuevoItemDeclaracionControles, "/// </remarks>");
                AgregarLinea(sbNuevoItemDeclaracionControles, string.Format("protected global::System.Web.UI.WebControls.TextBox txtNew{0}{1};{2}", objeto.Nombre, propiedad.Nombre, Environment.NewLine));
                
                //  Editar item
                AgregarLinea(sbEditarItemDeclaracionControles, "/// <summary>");
                AgregarLinea(sbEditarItemDeclaracionControles, string.Format("/// {0}Edit{1}{2} control.", controlPrefijo, objeto.Nombre, propiedad.Nombre));
                AgregarLinea(sbEditarItemDeclaracionControles, "/// </summary>");
                AgregarLinea(sbEditarItemDeclaracionControles, "/// <remarks>");
                AgregarLinea(sbEditarItemDeclaracionControles, "/// Auto-generated field.");
                AgregarLinea(sbEditarItemDeclaracionControles, "/// To modify move field declaration from designer file to code-behind file.");
                AgregarLinea(sbEditarItemDeclaracionControles, "/// </remarks>");
                AgregarLinea(sbEditarItemDeclaracionControles, string.Format("protected global::System.Web.UI.WebControls.{0} {1}Edit{2}{3};{4}", controlTipo, controlPrefijo, objeto.Nombre, propiedad.Nombre, Environment.NewLine));
                //--------------------------------------------------------------------------------------
            }

            plantilla.EstablecerCampo("NuevoItemDeclaracionControles", ObtenerString(sbNuevoItemDeclaracionControles));
            plantilla.EstablecerCampo("EditarItemDeclaracionControles", ObtenerString(sbEditarItemDeclaracionControles));

            GenerarArchivoWeb(objeto, plantilla, "ViewAll.aspx.designer");
        }

        private string ObtenerParametroDeMaterializacion(Propiedad propiedad)
        {
            string reader = string.Format("reader[Schema.{0}.SinFormato]", propiedad.Nombre);

            if (propiedad.Tipo == "object")
                return reader + ",";

            string convertType = string.Empty;
            switch(propiedad.Tipo)
            {
                case "string":
                    convertType = "String";
                    break;
                case "int":
                    convertType = "Int32";
                    break;
                case "DateTime":
                    convertType = "DateTime";
                    break;
                case "bool":
                    convertType = "Boolean";
                    break;
                case "double":
                    convertType = "Double";
                    break;
                default:
                    throw new Exception("Tipo de propiedad no válido.");
            }

            return string.Format("Convert.To{0}({1}),", convertType, reader);
        }

        private void GenerarArchivoLib(Objeto objeto, Plantilla plantilla, string nombreArchivo)
        {
            GenerarArchivo(objeto, plantilla, string.Format(@"Lib\{0}.cs", nombreArchivo));
        }

        private void GenerarArchivoWeb(Objeto objeto, Plantilla plantilla, string nombreArchivo)
        {
            GenerarArchivo(objeto, plantilla, string.Format(@"Web\{0}\{1}.cs", objeto.NombrePlural, nombreArchivo));
        }
    }

    /// <summary>
    /// Genera archivos de código JavaScript.
    /// </summary>
    public class GeneradorCodigoJS : GeneradorCodigo
    {
        public GeneradorCodigoJS()
        { }

        public void GenerarCodigoVerTodos(Objeto objeto)
        {
            var plantilla = Internal_Plantillas.ObtenerPlantillaJs(PlantillaJSNombre.ViewAll);

            plantilla.EstablecerCampo("Nombre", objeto.Nombre);
            plantilla.EstablecerCampo("NombrePlural", objeto.NombrePlural);

            var sbNuevoItemDeclaracionCampos = new StringBuilder();
            var sbEditarItemDeclaracionCampos = new StringBuilder();
            var sbNuevoItemInicializacionCampos = new StringBuilder();
            var sbEditarItemInicializacionCampos = new StringBuilder();
            var sbNuevoItemLimpiarCampos = new StringBuilder();
            var sbEditarItemLimpiarCampos = new StringBuilder();
            var sbNuevoItemValidarCampos = new StringBuilder();
            var sbEditarItemValidarCampos = new StringBuilder();
            var sbEditarItemVerificarDatosEnCampos = new StringBuilder();

            _tabs = 1;
            foreach (var propiedad in objeto.Propiedades)
            {
                //  DECLARACION DE CAMPOS DEL ITEM A AGREGAR
                //--------------------------------------------------------------------------------------
                string controlPrefijo = string.Empty;
                string controlValor = string.Empty;
                if (propiedad.SoloLectura)
                {
                    controlPrefijo = string.Format("lbl");
                    controlValor = "html";
                }
                else
                {
                    controlPrefijo = string.Format("txt");
                    controlValor = "val";
                }
                
                //  Nuevo item
                AgregarLinea(sbNuevoItemDeclaracionCampos, string.Format("txtNew{0}{1},", objeto.Nombre, propiedad.Nombre));
                
                //  Editar item
                AgregarLinea(sbEditarItemDeclaracionCampos, string.Format("{0}Edit{1}{2},", controlPrefijo, objeto.Nombre, propiedad.Nombre));
                //--------------------------------------------------------------------------------------

                //  INICIALIZACION DE CAMPOS DEL ITEM A EDITAR
                //--------------------------------------------------------------------------------------
                //  Nuevo item
                AgregarLinea(sbNuevoItemInicializacionCampos, string.Format("txtNew{0}{1} = $(\"#txtNew{0}{1}\");", objeto.Nombre, propiedad.Nombre));
                
                //  Editar item
                AgregarLinea(sbEditarItemInicializacionCampos, string.Format("{0}Edit{1}{2} = $(\"#{0}Edit{1}{2}\");", controlPrefijo, objeto.Nombre, propiedad.Nombre));
                //--------------------------------------------------------------------------------------

                //  LIMPIAR VALORES DE CAMPOS
                //--------------------------------------------------------------------------------------
                //  Nuevo item
                AgregarLinea(sbNuevoItemLimpiarCampos, string.Format("txtNew{0}{1}.val(\"\");", objeto.Nombre, propiedad.Nombre));

                //  Editar item
                AgregarLinea(sbEditarItemLimpiarCampos, string.Format("{0}Edit{1}{2}.{3}(\"\");", controlPrefijo, objeto.Nombre, propiedad.Nombre, controlValor));
                //--------------------------------------------------------------------------------------

                //  VALIDAR CAMPOS
                //--------------------------------------------------------------------------------------
                //  Editar item
                Agregar(sbEditarItemValidarCampos, string.Format("{0}Edit{1}{2}.length == 0 || ", controlPrefijo, objeto.Nombre, propiedad.Nombre));
                //--------------------------------------------------------------------------------------

                //  VERIFICAR DATOS EN CAMPOS
                //--------------------------------------------------------------------------------------
                //  Editar item
                Agregar(sbEditarItemVerificarDatosEnCampos, string.Format("{0}Edit{1}{2}.{3}() != \"\" || ", controlPrefijo, objeto.Nombre, propiedad.Nombre, controlValor));
            }

            plantilla.EstablecerCampo("NuevoItemDeclaracionCampos", ObtenerString(sbNuevoItemDeclaracionCampos, Environment.NewLine));
            plantilla.EstablecerCampo("EditarItemDeclaracionCampos", ObtenerString(sbEditarItemDeclaracionCampos, Environment.NewLine));
            plantilla.EstablecerCampo("NuevoItemInicializacionCampos", ObtenerString(sbNuevoItemInicializacionCampos, Environment.NewLine));
            plantilla.EstablecerCampo("EditarItemInicializacionCampos", ObtenerString(sbEditarItemInicializacionCampos, Environment.NewLine));
            plantilla.EstablecerCampo("NuevoItemLimpiarCampos", ObtenerString(sbNuevoItemLimpiarCampos, Environment.NewLine));
            plantilla.EstablecerCampo("EditarItemLimpiarCampos", ObtenerString(sbEditarItemLimpiarCampos, Environment.NewLine));
            plantilla.EstablecerCampo("EditarItemValidarCampos", ObtenerString(sbEditarItemValidarCampos, " || "));
            plantilla.EstablecerCampo("EditarItemVerificarDatosEnCampos", ObtenerString(sbEditarItemVerificarDatosEnCampos, " || "));

            GenerarArchivoScripts(objeto, plantilla, "ViewAll");
        }

        private void GenerarArchivoScripts(Objeto objeto, Plantilla plantilla, string nombreArchivo)
        {
            GenerarArchivo(objeto, plantilla, string.Format(@"Web\scripts\pages\{0}\{1}.js", objeto.NombrePlural, nombreArchivo));
        }
    }

    /// <summary>
    /// Genera archivos de código ASPX.
    /// </summary>
    public class GeneradorCodigoASPX : GeneradorCodigo
    {
        public GeneradorCodigoASPX()
        { }

        public void GenerarPaginaWebVerTodos(Objeto objeto)
        {
            var plantilla = Internal_Plantillas.ObtenerPlantillaAspx(PlantillaASPXNombre.ViewAll);

            plantilla.EstablecerCampo("Namespace", objeto.EspacioDeNombre);
            plantilla.EstablecerCampo("Nombre", objeto.Nombre);
            plantilla.EstablecerCampo("NombrePlural", objeto.NombrePlural);

            var sbCamposEnlazadosGrid = new StringBuilder();
            var sbNuevoItemCampos = new StringBuilder();
            var sbEditarItemCampos = new StringBuilder();

            _tabs = 0;
            foreach (var propiedad in objeto.Propiedades)
            {
                //  CAMPO ENLAZADO DEL GRID
                //--------------------------------------------------------------------------------------
                _tabs = 4;
                AgregarLinea(sbCamposEnlazadosGrid, string.Format("<asp:BoundField DataField=\"{0}\" HeaderText=\"{0}\" SortExpression=\"{0}\" />", propiedad.Nombre));
                //--------------------------------------------------------------------------------------

                //  CAMPO DEL ITEM A AGREGAR
                //--------------------------------------------------------------------------------------
                _tabs = 5;
                AgregarLinea(sbNuevoItemCampos, string.Format("<div class=\"form-item\"><span class=\"form-item-name\">{1}:</span><span class=\"form-item-value\"><asp:TextBox runat=\"server\" ID=\"txtNew{0}{1}\" ClientIDMode=\"Static\" /></span></div>", objeto.Nombre, propiedad.Nombre));
                //--------------------------------------------------------------------------------------

                //  CAMPO DEL ITEM A EDITAR
                //--------------------------------------------------------------------------------------
                string controlValorCampo = string.Empty;
                if (!propiedad.SoloLectura)
                    controlValorCampo = string.Format("<asp:TextBox runat=\"server\" ID=\"txtEdit{0}{1}\" ClientIDMode=\"Static\" />", objeto.Nombre, propiedad.Nombre);
                else
                    controlValorCampo = string.Format("<asp:Label runat=\"server\" ID=\"lblEdit{0}{1}\" ClientIDMode=\"Static\" />", objeto.Nombre, propiedad.Nombre);

                AgregarLinea(sbEditarItemCampos, string.Format("<div class=\"form-item\"><span class=\"form-item-name\">{0}:</span><span class=\"form-item-value\">{1}</span></div>", propiedad.Nombre, controlValorCampo));
                //--------------------------------------------------------------------------------------
            }

            plantilla.EstablecerCampo("CamposEnlazadosGrid", ObtenerString(sbCamposEnlazadosGrid, Environment.NewLine));
            plantilla.EstablecerCampo("NuevoItemCampos", ObtenerString(sbNuevoItemCampos, Environment.NewLine));
            plantilla.EstablecerCampo("EditarItemCampos", ObtenerString(sbEditarItemCampos, Environment.NewLine));

            GenerarArchivo(objeto, plantilla, string.Format(@"Web\{0}\ViewAll.aspx", objeto.NombrePlural));
        }
    }

    /// <summary>
    /// Genera archivos de código CSS.
    /// </summary>
    public class GeneradorCodigoCSS : GeneradorCodigo
    {
        public GeneradorCodigoCSS()
        { }

        public void GenerarCodigoVerTodos(Objeto objeto)
        {
            var plantilla = Internal_Plantillas.ObtenerPlantillaCss(PlantillaCSSNombre.ViewAll);

            plantilla.EstablecerCampo("NombrePlural", objeto.NombrePlural);

            GenerarArchivo(objeto, plantilla, string.Format(@"Web\styles\pages\{0}\ViewAll.css", objeto.NombrePlural));
        }
    }
}
